#include "as-node.h"

namespace tinyscript{
namespace internal{

ASNodePage* ASNode::kNodePage= NULL;

ASNode::~ASNode() {}

ASNodePage::ASNodePage():
    base_pool_(64,sizeof(base_pool_)) {
    mempool_list_.resize(64);
}

void* ASNodePage::New( size_t size ) {
    assert( size <= kMaxPageObjectSize );
    int idx = Round(size)/kAlignmentSize;
    if( mempool_list_[idx] == NULL )
        mempool_list_[idx] = new (base_pool_.New()) ASNodeMemoryPool(NODE_CACHE_SIZE,Round(size));
    return mempool_list_[idx]->New();
}

void ASNodePage::Delete(size_t size, void* ptr ) {
    if( ptr == NULL )
        return;
    assert( size <= kMaxPageObjectSize );
    int idx = Round(size)/kAlignmentSize;
    assert( mempool_list_[idx] != NULL );
    mempool_list_[idx]->Delete(ptr);
}

NodeUnary::~NodeUnary() {
    delete child_;
}

NodeExpression::~NodeExpression() {
    delete left_child_;
    delete right_child_;
}

NodeFuncInvoke::~NodeFuncInvoke() {
    for( NodeList::iterator b = node_list_.begin() ; b != node_list_.end() ; ++b ) {
        delete *b;
    }
}

void NodeFuncInvoke::PrintNode( std::ostream& os, int level ) {
	PrintPrefix(os,level);
	os<<"Function Invoke:{\n";
	PrintPrefix(os,level);
	os<<"Function Name:"<<func_name_<<"\n";
	PrintPrefix(os,level);
	os<<"Parameter List:\n";
	for( NodeList::iterator i = node_list_.begin() ; i != node_list_.end() ; ++i ) {
		(*i)->PrintNode(os,level+1);
	}
	PrintPrefix(os,level);
	os<<"}\n";
}

NodeAssignment::~NodeAssignment() {
    delete left_child_;
    delete right_child_;
}

NodeIf::~NodeIf() {
    delete condition_node_;
    delete body_;
    for( NodeList::iterator i = branch_list_.begin() ; i != branch_list_.end() ; ++i ) {
        delete *i;
    }
}

void NodeIf::PrintNode(std::ostream& os , int level /* = 0 */) {
	PrintPrefix(os,level);
	os<<"If:{\n";
	PrintPrefix(os,level);
	os<<"Condition:\n";
	condition_node_->PrintNode(os,level+1);
	PrintPrefix(os,level);
	os<<"Body:\n";
	body_->PrintNode(os,level+1);
	for( NodeList::iterator i = branch_list_.begin() ; 
		i!= branch_list_.end() ; ++i ) {
			(*i)->PrintNode(os,level+1);
	}
	PrintPrefix(os,level);
	os<<"}\n";

}

NodeElseIf::~NodeElseIf() {
	delete body_;
	delete condition_node_;
}

NodeElse::~NodeElse() {
	delete body_;
}

NodeFor::~NodeFor() {
    delete body_;
    delete initial_node_;
    delete step_node_;
    delete condition_node_;
}

NodeForeach::~NodeForeach() {
    delete list_node_;
    delete body_;
}

NodeWhile::~NodeWhile() {
    delete condition_node_;
    delete body_;
}

void NodeWhile::PrintNode(std::ostream& os , int level ) {
	PrintPrefix(os,level);
	os<<"While:{\n";
	PrintPrefix(os,level);
	os<<"Condition:\n";
	condition_node_->PrintNode(os,level+1);
	PrintPrefix(os,level);
	body_->PrintNode(os,level+1);
	PrintPrefix(os,level);
	os<<"}\n";
}

NodeDefineFunc::~NodeDefineFunc() {
    delete func_name_;
    delete body_;
    for( NodeList::iterator i = parameter_list_.begin() ; i != parameter_list_.end() ; ++i ) {
        delete *i;
    }
}

void NodeDefineFunc::PrintNode(std::ostream& os , int level ) {
	PrintPrefix(os,level);
	os<<"DefineFunc:{\n";
	PrintPrefix(os,level);
	os<<"FuncParameterList:\n";
	for( NodeList::iterator i = parameter_list_.begin() ; i != parameter_list_.end() ; ++i ) {
		(*i)->PrintNode(os,level+1);
	}
	PrintPrefix(os,level);
	os<<"Body:\n";
	body_->PrintNode(os,level+1);
	PrintPrefix(os,level);
	os<<"}\n";
}

NodeDefineList::~NodeDefineList() {
    for( DefineList::iterator i = define_list_.begin() ; 
		i != define_list_.end() ; ++i ) {
        delete (*i);
    }
}

bool NodeDefineList::AppendDefinition( ASNode* n ) {
	// This node must be a assignment node
	NodeDefineListAssignment* assign = n->EnsureCast<NodeDefineListAssignment>();
	ASNode* name = assign->name();
	// Testing the index validation
	switch( name->node_type() ) {
	case ASNode::NODE_INT: {
			int index = name->EnsureCast<NodeInt>()->value();
			std::pair< IndexList::iterator , bool > iret = index_list_.insert(index);
			if( !iret.second )
				return false;
			break;
		}
	case ASNode::NODE_STRING: {
			std::string key = name->EnsureCast<NodeString>()->value();
			std::pair< KeyList::iterator , bool > iret = key_list_.insert( key );
			if( !iret.second )
				return false;
			break;
	    }
	case ASNode::NODE_SYMBOL: {
			std::string key = name->EnsureCast<NodeSymbol>()->variable_name();
			std::pair< KeyList::iterator , bool > iret = key_list_.insert( key );
			if( !iret.second )
				return false;
			break;
	    }
	default:
		assert(0);
	}
	define_list_.push_back(n);
	return true;
}

void NodeDefineList::PrintNode( std::ostream& os , int level ) {
	PrintPrefix(os,level);
	os<<"List:{\n";
	for( DefineList::iterator ib = define_list_.begin() ; 
		ib != define_list_.end() ; ++ib ) {
			(*ib)->PrintNode(os,level+1);
	}
	PrintPrefix(os,level);
	os<<"}\n";
}

NodeDefineListAssignment::~NodeDefineListAssignment() { 
	delete name_;
	delete value_node_;
}

NodeListAccessor::~NodeListAccessor() {
	delete index_node_;
}

NodeChunk::~NodeChunk() {
	for( NodeList::iterator ib = node_list_.begin() ; ib != node_list_.end() ; ++ib ) {
		delete *ib;
	}
}

void NodeChunk::PrintNode(std::ostream& os , int level ) {
	PrintPrefix(os,level);
	os<<"CodeBlock:{\n";
	PrintPrefix(os,level);
	for( NodeList::iterator ib = node_list_.begin() ; ib != node_list_.end() ; ++ib ) {
		(*ib)->PrintNode(os,level+1);
	}
	PrintPrefix(os,level);
	os<<"}\n";
}

}// namespace internal
}// namespace tinyscript
